home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / audio / DAT / dodat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  38.7 KB  |  1,524 lines

  1. /*
  2.  * A program to go between disk files and DAT tapes.
  3.  *
  4.  * This program accepts a simple scripting language to
  5.  * decide where to place files onto DAT, how much silence
  6.  * to insert between tracks, etc.
  7.  *
  8.  * This program requires IRIX 5.X and an audio-capable DAT
  9.  * drive with firmware revision 2.63 or greater. Firmware 
  10.  * revisions greater than 2.72 have additional support.
  11.  *
  12.  * Doug Cook
  13.  * Silicon Graphics, Inc., December 1993
  14.  *
  15.  * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
  16.  * ALL RIGHTS RESERVED
  17.  * Permission to use, copy, modify, and distribute this software for
  18.  * any purpose and without fee is hereby granted, provided that the above
  19.  * copyright notice appear in all copies and that both the copyright notice
  20.  * and this permission notice appear in supporting documentation, and that
  21.  * the name of Silicon Graphics, Inc. not be used in advertising
  22.  * or publicity pertaining to distribution of the software without specific,
  23.  * written prior permission.
  24.  *
  25.  * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
  26.  * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
  27.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
  28.  * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
  29.  * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
  30.  * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
  31.  * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
  32.  * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
  33.  * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
  34.  * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
  35.  * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
  36.  * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
  37.  *
  38.  * US Government Users Restricted Rights
  39.  * Use, duplication, or disclosure by the Government is subject to
  40.  * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
  41.  * (c)(1)(ii) of the Rights in Technical Data and Computer Software
  42.  * clause at DFARS 252.227-7013 and/or in similar or successor
  43.  * clauses in the FAR or the DOD or NASA FAR Supplement.
  44.  * Unpublished-- rights reserved under the copyright laws of the
  45.  * United States.  Contractor/manufacturer is Silicon Graphics,
  46.  * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
  47.  *
  48.  *
  49.  */
  50.  
  51. #include <sys/types.h>
  52. #include <sys/errno.h>
  53. #include <sys/tpsc.h>
  54. #include <sys/mtio.h>
  55. #include <sys/prctl.h>
  56. #include <fcntl.h>
  57. #include <dataudio.h>
  58. #include <stdio.h>
  59. #include <audio.h>
  60. #include <audiofile.h>
  61.  
  62. #define OP_READ        1
  63. #define OP_WRITE     2
  64. #define OP_SEEK     4
  65.  
  66. int dat;            /* dat tape fd */
  67.  
  68. static char *datdev = "/dev/nrtape";
  69.  
  70. /*
  71.  * tape_pos_unknown indicates that the current value of timecode(s) and
  72.  * program number/index number on the tape (i.e. the current position) is not 
  73.  * known. This is normally the case immediately following a seek 
  74.  * operation (for example, if you seek by a-time, the ptime and program number
  75.  * are unknown). We need to know the position before we can do a write, so
  76.  * we can put the correct timecodes and program information in the frames we 
  77.  * write. 
  78.  */
  79. static int tape_pos_unknown = 1;
  80.  
  81. /*
  82.  * last_cmd stores the last command that was issued to the tape. In theory,
  83.  * this should not matter. In practice, however, we need to work around
  84.  * DAT firmware bugs. Writes which immediately follow a read do not append
  85.  * correctly (2.63). Writes which immediately follow a seek don't work correctly
  86.  * (2.63). Read-position only works following seeks on 2.72 and not at all on 2.63.
  87.  */
  88. static int last_cmd = OP_SEEK;
  89.  
  90. static int startidframes = 0;
  91. static int verbose = 1;        /* default is VERBOSE mode */
  92. static int maxretry = 10;    /* by default we will attempt to retry seeks 10 times */
  93. static int new_firmware;
  94. static int samps_per_frame = DTDA_NUMSAMPS44K;
  95. static int program = 1, index = 1;
  96.  
  97. /*
  98.  * outframe is our "template" frame. We modify the fields we need and
  99.  * insert the appropriate audio each time we write a frame to the tape.
  100.  */
  101. static DTFRAME outframe;
  102. /*
  103.  * inframe is the last frame that we read from the tape. We can use this
  104.  * to determine our position if last_cmd = OP_READ.
  105.  */
  106. static DTFRAME inframe;
  107.  
  108. /*
  109.  * we include our own DTframetohmsf because IRIX versions prior to
  110.  * 5.2 DMDEV have a slight bug in this function. We also include
  111.  * DTframetotc since it depends upon correct functioning of frametohmsf.
  112.  */
  113.  
  114. void
  115. myDTframetohmsf(unsigned long fr, int *h,int *m, int *s, int *f)
  116. {
  117.     unsigned long mrem,hrem;
  118.     *h = fr / 120000;
  119.     hrem = fr % 120000;
  120.     *m = hrem / 2000;
  121.     mrem = hrem % 2000;
  122.     *s = (2+(mrem * 3)) / 100;
  123.     *f = mrem - (100 * *s) / 3;
  124. }
  125.  
  126. void
  127. myDTframetotc(unsigned long fr, struct dttimecode* tc)
  128. {
  129.     int h,m,s,f;
  130.     myDTframetohmsf(fr,&h,&m,&s,&f);
  131.     /*
  132.      * now set the msf fields in the timecode. These are in BCD;
  133.      */
  134.     tc->hhi = h / 10;
  135.     tc->hlo = h % 10;
  136.     tc->mhi = m / 10;
  137.     tc->mlo = m % 10;
  138.     tc->shi = s / 10;
  139.     tc->slo = s % 10;
  140.     tc->fhi = f / 10;
  141.     tc->flo = f % 10;
  142. }
  143.  
  144. void
  145. print_frame(DTFRAME *frame, char *msg)
  146. {
  147.     struct dttimepack *tpp;
  148.     
  149.     char *str="--:--:--:--";
  150.     tpp = (struct dttimepack *)&(frame->subcode.packs[DTP_ATIME-1]);
  151.     DTtimetoa(str,&tpp->tc);
  152.     printf("%s prog %d index %d atime %s",msg, program,index,str);
  153.     tpp = (struct dttimepack *)&(frame->subcode.packs[DTP_PTIME-1]);
  154.     DTtimetoa(str,&tpp->tc);
  155.     printf(" ptime %s\n",str);
  156. }
  157.  
  158. int 
  159. get_firmware_revision(int fd, int *maj, int *min)
  160. {
  161.     ct_g0inq_data_t info;
  162.     char revbuf1[MAX_INQ_PRL + 1];
  163.  
  164.     /*
  165.      * get the DAT drive firmware revision.
  166.      */
  167.     if (ioctl(fd, MTSCSIINQ, &info) >= 0) {
  168.         strncpy(revbuf1, (char *)info.id_prl, MAX_INQ_PRL);
  169.         *maj = atoi(strtok(revbuf1, "."));
  170.         *min = atoi(strtok(NULL, "."));
  171.         return 0;
  172.     }
  173.     else {
  174.         return -1;     /*ioctl failed */
  175.     }
  176. }
  177.  
  178. void
  179. reset_timecodes()
  180. {
  181.     struct dttimecode *tcp;
  182.     struct dttimepack *tpp;
  183.     struct dttimepack *tpp1;
  184.  
  185.     /*
  186.      * set up the subcode bits
  187.      */
  188.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  189.     bzero(&tpp->tc,sizeof(struct dttimecode));
  190.     tpp->id = DTP_ATIME;
  191.  
  192.     tpp->index.dhi = 0;
  193.     tpp->index.dlo = 1;
  194.     tpp->pno1 = outframe.subcode.sid.pno1 = 0;
  195.     tpp->pno2 = outframe.subcode.sid.pno2 = 0;
  196.     tpp->pno3 = outframe.subcode.sid.pno3 = 1;
  197.     tpp1 = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  198.     *tpp1 = *tpp;
  199.     tpp1->id = DTP_PTIME;
  200.  
  201.     /* numpacks tells how many packs are written onto the DAT */
  202.     outframe.subcode.sid.numpacks = 2;    /* ATIME is 2, PTIME is 1 */
  203. }
  204.  
  205. void
  206. copy_prohibit(int p)
  207. {
  208.     outframe.subcode.mid.copy = (p == 0) ? DTM_COPY_PERMITTED : DTM_COPY_PROHIBITED;
  209. }
  210.  
  211. int
  212. write_eot(int fd)
  213. {
  214.     int i;
  215.     struct dttimepack *tpp;
  216.     struct dttimecode *tcp;
  217.  
  218.     if (verbose) {
  219.         printf("writing lead-out...");
  220.         fflush(stdout);
  221.     }
  222.  
  223.     /*
  224.      * Set the lead-out subcodes in our template frame
  225.      */
  226.     outframe.subcode.sid.pno1 = 0;
  227.     outframe.subcode.sid.pno2 = outframe.subcode.sid.pno3 = 0xE;   /* EOT */
  228.     outframe.subcode.sid.ctrlid =  DTS_START;
  229.  
  230.     /*
  231.      * Mark the timecodes as invalid. 
  232.      * Also put 0xEE into the pno in the packs, indicating EOT. This 
  233.      * covers us no matter where a given drive snags its pno.
  234.      */
  235.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  236.     tcp = &tpp->tc;
  237.     tcp->hhi = tcp->hlo =
  238.     tcp->mhi = tcp->mlo = tcp->shi = tcp->slo = tcp->fhi = tcp->flo = 0xA;
  239.     tpp->pno1 = 0;
  240.     tpp->pno2 = tpp->pno3 = 0xE;   /* EOT */
  241.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  242.     tcp = &tpp->tc;
  243.     tcp->hhi = tcp->hlo =
  244.     tcp->mhi = tcp->mlo = tcp->shi = tcp->slo = tcp->fhi = tcp->flo = 0xA;
  245.     tpp->pno1 = 0;
  246.     tpp->pno2 = tpp->pno3 = 0xE;   /* EOT */
  247.  
  248.     /*
  249.      * zero the audio data in the template frame
  250.      */
  251.     bzero(&outframe.audio,DTDA_DATASIZE);
  252.  
  253.     /*
  254.      * Write this dummy frame to the tape to make the trailer
  255.      * DAT spec sez lead-out must be >=300 frames
  256.      */
  257.     for (i = 0; i < 300; i++) {
  258.         if ((write(fd, &outframe, sizeof(DTFRAME))) < 0) {
  259.             perror("tape write failed on trailer");
  260.             return 0;
  261.         }
  262.     }
  263.     
  264.     reset_timecodes();
  265.  
  266.     if (verbose) {
  267.         printf("done.\n");
  268.     }
  269. }
  270.  
  271. /*
  272.  * Due to a bug in the DAT firmware prior to 2.72, the following method of 
  273.  * getting time from the tape does NOT generally work. However, reading a 
  274.  * frame and decoding the timecode works fine. 
  275.  */
  276. int
  277. read_position(fd)
  278. {
  279.     struct mtaudio mt_aud;
  280.     int pn;
  281.     char *s = "--:--:--:--";
  282.  
  283.     if (ioctl(fd, MTGETAUDIO, &mt_aud) >= 0) {
  284.     pn = DTpnotodec(mt_aud.pno1, mt_aud.pno2, mt_aud.pno3);
  285.  
  286.     DTtimetoa(s,&mt_aud.atime);
  287.     printf("DAT pos (read position) prog %d atime %s",pn,s);
  288.     DTtimetoa(s,&mt_aud.ptime);
  289.     printf(" ptime %s\n",s);
  290.     }
  291. }
  292.  
  293. int
  294. perform_seek(int fd, struct mtaudio *mt_aud, int nretries)
  295. {
  296.     struct mtaudio newpos;
  297.     struct mtget mt_get;
  298.     int seekfail=0;
  299.  
  300.     do {
  301.     if (seekfail && verbose) {
  302.         printf("retry...");
  303.         fflush(stdout);
  304.     }
  305.     seekfail = 0;
  306.     
  307.     /*
  308.      * start the seek.
  309.      */
  310.     if (ioctl(fd, MTSETAUDIO, mt_aud) < 0) {
  311.         perror("DAT seek failed");
  312.         return 0;
  313.     }
  314.     
  315.     tape_pos_unknown = 1;
  316.     last_cmd = OP_SEEK;
  317.     
  318.     /*
  319.      * wait for the seek to complete.
  320.      */
  321.     do {
  322.         if (ioctl(fd, MTIOCGET, &mt_get) < 0) {
  323.         perror("DAT seek failed");
  324.         return 0;
  325.         }
  326.     } while (mt_get.mt_erreg & (CT_SEEKING >> 16));
  327.     
  328.     /*
  329.      * Now see if we ended up where we wanted to be.
  330.      * If not, we'll set seekfail, and retry if specified.
  331.      */
  332.     if (ioctl(fd, MTGETAUDIO, &newpos) >= 0) {
  333.         if (mt_aud->seektype == MTAUDPOSN_ABS) {
  334.         if (DTtctoframe(&newpos.atime) != DTtctoframe(&mt_aud->atime)) {
  335.             /* 
  336.              * atime of read position does not match destination:
  337.              * therefore seek failed to go whither we wished.
  338.              */
  339.             seekfail = 1;
  340.         }
  341.         }
  342.         else if (mt_aud->seektype == MTAUDPOSN_PTIME) {
  343.         if (DTtctoframe(&newpos.ptime) != DTtctoframe(&mt_aud->ptime)) {
  344.             /* 
  345.              * ptime of read position does not match destination:
  346.              * therefore seek failed to go whither we wished.
  347.              */
  348.             seekfail = 1;
  349.         }
  350.         }
  351.         else if (mt_aud->seektype == MTAUDPOSN_PROG) {
  352.         if (DTpnotodec(mt_aud->pno1, mt_aud->pno2, mt_aud->pno3) !=
  353.             DTpnotodec(newpos.pno1, newpos.pno2, newpos.pno3)) {
  354.             /* 
  355.              * prog of read position does not match destination:
  356.              * therefore seek failed to go whither we wished.
  357.              */
  358.             seekfail = 1;
  359.         }
  360.         }
  361.     }
  362.     else {
  363.         /* read position failed; let's abort */
  364.         return 0;
  365.     }
  366.     
  367.     } while (seekfail && nretries-- > 0);
  368.  
  369.     /* XXX on new firmware we can set current position 'cos read pos works */
  370.     return (seekfail) ? 0 : 1;
  371. }
  372.  
  373.  
  374. int
  375. seek_time(int fd,int atime,int h,int m, int s, int f)
  376. {
  377.     struct mtaudio mt_aud;
  378.     long frame;
  379.  
  380.     mt_aud.zero1 = 0;    /* one must clear the zero fields, or pno is invalid */
  381.     mt_aud.zero2 = 0;
  382.     mt_aud.zero3 = 0;
  383.  
  384.     /* convert hmsf to tc using two DAT lib calls. */
  385.     if (atime) {
  386.         char *st = "--:--:--:--";
  387.         mt_aud.seektype = MTAUDPOSN_ABS;
  388.         myDTframetotc(DThmsftoframe(h,m,s,f),&mt_aud.atime);
  389.         if (verbose) {
  390.         DTtimetoa(st,&mt_aud.atime);
  391.             printf("seeking to atime %s... ",st);
  392.             fflush(stdout);
  393.         }
  394.     }
  395.     else {
  396.         char *st = "--:--:--:--";
  397.         mt_aud.seektype = MTAUDPOSN_PTIME;
  398.         myDTframetotc(DThmsftoframe(h,m,s,f),&mt_aud.ptime);
  399.         if (verbose) {
  400.         DTtimetoa(st,&mt_aud.ptime);
  401.             printf("seeking to ptime %s... ",st);
  402.             fflush(stdout);
  403.         }
  404.     }
  405.  
  406.     if (perform_seek(fd,&mt_aud, maxretry) == 0) {
  407.     fprintf(stderr,"seek failed.\n");
  408.     return 0;
  409.     }
  410.  
  411.     if (verbose) {
  412.     printf("done\n");
  413.     }
  414.  
  415.     return 1;
  416. }
  417.  
  418. int
  419. seek_to_last_read(int fd, int writeback)
  420. {
  421.     struct mtaudio mt_aud;
  422.     struct dttimepack *tpp;
  423.  
  424.     mt_aud.seektype = MTAUDPOSN_ABS;
  425.     tpp = (struct dttimepack *)&inframe.subcode.packs[DTP_ATIME-1];
  426.     mt_aud.atime = tpp->tc;
  427.  
  428.     if (verbose) {
  429.         char *st = "--:--:--:--";
  430.         DTtimetoa(st,&mt_aud.atime);
  431.     printf("seeking to atime %s... ",st);
  432.         fflush(stdout);
  433.     }
  434.  
  435.     if (perform_seek(fd, &mt_aud, maxretry) == 0) {
  436.     fprintf(stderr,"seek failed.\n");
  437.     return 0;
  438.     }
  439.  
  440.     tape_pos_unknown = 0;
  441.  
  442.     if (writeback) {
  443.     /*
  444.      * in some cases we need to write back the last-read
  445.      * frame. This occurs when we want to append to the tape:
  446.      * we have read the last good frame on the tape, we need to
  447.      * seek back to the beginning of that frame, write it back,
  448.      * and then write the new data. This tries to work around the 
  449.      * back-to-back read/write firmware bug.
  450.      */
  451.         last_cmd = OP_WRITE;
  452.     if (verbose) printf("writing back frame...\n");
  453.         if ((write(fd, &inframe, sizeof(DTFRAME))) < 0) {
  454.         perror("can't write back last read frame:");
  455.         return 0;
  456.     }
  457.     }
  458.     return 1;
  459. }
  460.  
  461. int
  462. get_tape_pos(int fd, int move_tape)
  463. {
  464.     struct mtaudio mt_aud;
  465.     struct mtget mt_get;
  466.     struct dttimepack *tpp;
  467.     struct dttimepack *tpp1;
  468.     struct dttimecode *tcp;
  469.     struct dttimecode *tcp1;
  470.     int i;
  471.     int need_writeback = 1;
  472.  
  473.     if (!move_tape && new_firmware && last_cmd == OP_SEEK) {
  474.     /*
  475.      * We have new firmware that is capable of giving correct
  476.      * position information without moving the tape -- well,  only
  477.      * after a seek (but after a read or write we *know* where we are). Let's use
  478.      * this snazzy feature.
  479.      */
  480.     if (ioctl(fd, MTGETAUDIO, &mt_aud) >= 0) {
  481.         program = DTpnotodec(mt_aud.pno1, mt_aud.pno2, mt_aud.pno3);
  482.     
  483.         outframe.subcode.sid.pno1 = mt_aud.pno1;
  484.         outframe.subcode.sid.pno2 = mt_aud.pno2;
  485.         outframe.subcode.sid.pno3 = mt_aud.pno3;
  486.         
  487.         tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  488.         tpp->pno1 = mt_aud.pno1;
  489.         tpp->pno2 = mt_aud.pno2;
  490.         tpp->pno3 = mt_aud.pno3;
  491.         tpp->index.dhi = mt_aud.indexhi;
  492.         tpp->index.dlo = mt_aud.index;
  493.         tpp->tc = mt_aud.ptime;
  494.         tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  495.         tpp->pno1 = mt_aud.pno1;
  496.         tpp->pno2 = mt_aud.pno2;
  497.         tpp->pno3 = mt_aud.pno3;
  498.         tpp->index.dhi = mt_aud.indexhi;
  499.         tpp->index.dlo = mt_aud.index;
  500.         tpp->tc = mt_aud.atime;
  501.         if (verbose) {
  502.         print_frame(&outframe, "Current position:");
  503.         }
  504.         return 1;
  505.     }
  506.     else {
  507.         perror("Read position failed");
  508.         return 0;
  509.     }
  510.     }
  511.     
  512.     /*
  513.      * if we just did a read, we don't need a new frame of data.
  514.      * Otherwise, to figure out where we are, we must read a frame.
  515.      * move_tape set to 1 will force a read (and later re-seek to the
  516.      * beginning of the frame it just read).
  517.      */
  518.     if (move_tape || last_cmd != OP_READ) {
  519.         /*
  520.          * Now read the timecodes, program, index, etc.
  521.          * Alas! to do this accurately we must move the tape.
  522.          * We will therefore have to seek again after we do this.
  523.          */
  524.     if (verbose) printf("reading a frame...\n");
  525.         if ((read(fd, &inframe, sizeof(DTFRAME))) < 0) {
  526.             perror("tape read failed");
  527.             return 0;
  528.         }
  529.     need_writeback = 0;
  530.     last_cmd = OP_READ;
  531.     }
  532.     else if (verbose) printf("using the frame I just read...\n");
  533.  
  534.     /*
  535.      * get the program number from the frame
  536.      */
  537.     switch(inframe.subcode.sid.pno3) {
  538.     case 0xa :
  539.         /* unused program number -- ignore */
  540.         break;
  541.     case 0xb :
  542.         /* bot */
  543.         fprintf(stderr, "at BOT\n");
  544.         return 0;
  545.     case 0xe :
  546.         /* eot */
  547.         fprintf(stderr, "at EOT\n");
  548.         return 0;
  549.     default:
  550.             program = DTpnotodec(inframe.subcode.sid.pno1, 
  551.             inframe.subcode.sid.pno2, inframe.subcode.sid.pno3);
  552.  
  553.         outframe.subcode.sid.pno1 = inframe.subcode.sid.pno1;
  554.         outframe.subcode.sid.pno2 = inframe.subcode.sid.pno2;
  555.         outframe.subcode.sid.pno3 = inframe.subcode.sid.pno3;
  556.         break;
  557.     }
  558.     tpp1 = (struct dttimepack *)&inframe.subcode.packs[DTP_PTIME-1];
  559.     if (DTtcvalid(&(tpp1->tc))) {
  560.         tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  561.     *tpp = *tpp1;
  562.     }
  563.     else {
  564.     fprintf(stderr,"No valid ptime found at location -- setting ptime to 0\n");
  565.         tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  566.         tpp1 = (struct dttimepack *)&inframe.subcode.packs[DTP_PTIME-1];
  567.     tpp->pno1 = tpp1->pno1;
  568.     tpp->pno2 = tpp1->pno2;
  569.     tpp->pno3 = tpp1->pno3;
  570.     tpp->index = tpp1->index;
  571.     bzero(&tpp->tc,sizeof(struct dttimecode));
  572.     }
  573.     if ((i = DTbcdtodec(tpp1->index.dhi,tpp1->index.dlo)) < 100) {
  574.     index = i;
  575.     }
  576.     tpp1 = (struct dttimepack *)&inframe.subcode.packs[DTP_ATIME-1];
  577.     if (DTtcvalid(&(tpp1->tc))) {
  578.         tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  579.     *tpp = *tpp1;
  580.     }
  581.     else {
  582.     fprintf(stderr,"No valid atime found at location\n");
  583.         tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  584.         tpp1 = (struct dttimepack *)&inframe.subcode.packs[DTP_ATIME-1];
  585.     tpp->pno1 = tpp1->pno1;
  586.     tpp->pno2 = tpp1->pno2;
  587.     tpp->pno3 = tpp1->pno3;
  588.     tpp->index = tpp1->index;
  589.     /*
  590.      * If there's no valid A-time then we fail. We need valid
  591.      * a-time, if not just for re-seeking to this frame.
  592.      */
  593.         return 0;
  594.     }
  595.     if ((i = DTbcdtodec(tpp1->index.dhi,tpp1->index.dlo)) < 100) {
  596.     index = i;
  597.     }
  598.     if (verbose) {
  599.     print_frame(&outframe, "Current position:");
  600.     }
  601.  
  602.     if (new_firmware || move_tape || need_writeback) {
  603.     if (verbose) {
  604.         printf("correcting time for moved tape...\n");
  605.     }
  606.     /*
  607.      * if we are not going to move the tape back to where it was,
  608.      * at least adjust the time to reflect the correct timecode where
  609.      * we are.
  610.      */
  611.         tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  612.         tcp = &tpp->tc;
  613.         DTinctime(tcp);
  614.         /*
  615.          * The DAT spec states that when index=0, ptime stays
  616.          * at 0. We therefore only increment for a nonzero index.
  617.          */
  618.         if (index != 0) {
  619.             tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  620.             tcp = &tpp->tc;
  621.             DTinctime(tcp);
  622.         }
  623.     }
  624.  
  625.     return (!new_firmware && !move_tape) ? seek_to_last_read(fd,need_writeback) : 1;
  626. }
  627.  
  628. /*
  629.  * set_atime
  630.  *
  631.  * This allows you to set the atime to be written to the tape. Use this
  632.  * with caution. In most cases, you want the program to figure out what
  633.  * atime to write by making it contiguous with what's already on the tape.
  634.  * Discontinuous atimes make for an unhappy tape.
  635.  */
  636. void
  637. set_atime(int h, int m, int s, int f)
  638. {
  639.     struct dttimepack *tpp;
  640.     struct dttimecode *tcp;
  641.  
  642.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  643.     tcp = &(tpp->tc);
  644.  
  645.     /* warning! no validity check here */
  646.     myDTframetotc(DThmsftoframe(h,m,s,f),tcp);
  647.     if (verbose) {
  648.     print_frame(&outframe, "New position:");
  649.     }
  650.     tape_pos_unknown = 0;    /* we "know" where we are now, we just set it*/
  651. }
  652.  
  653. void
  654. set_ptime(int h, int m, int s, int f)
  655. {
  656.     struct dttimepack *tpp;
  657.     struct dttimecode *tcp;
  658.  
  659.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  660.     tcp = &(tpp->tc);
  661.  
  662.     /* warning! no validity check here */
  663.     myDTframetotc(DThmsftoframe(h,m,s,f),tcp);
  664.     if (verbose) {
  665.     print_frame(&outframe, "New position:");
  666.     }
  667. }
  668.  
  669. int
  670. seek_prog(int fd,int p)
  671. {
  672.     struct mtaudio mt_aud;
  673.     int pt;
  674.  
  675.     if (p == 0) {
  676.     p = program;
  677.     }
  678.  
  679.     if (verbose) {
  680.     printf("seeking to program %d ... ", p);
  681.         fflush(stdout);
  682.     }
  683.  
  684.     if (p > 799 || p < 0) {
  685.     fprintf(stderr,"Invalid location: program %d\n",p);
  686.     return 0;
  687.     }
  688.  
  689.     mt_aud.zero1 = 0;    /* one must clear the zero fields, or pno is invalid */
  690.     mt_aud.zero2 = 0;
  691.     mt_aud.zero3 = 0;
  692.     mt_aud.pno1 = p / 100;
  693.     pt = p % 100;
  694.     mt_aud.pno2 = pt / 10;
  695.     mt_aud.pno3 = pt % 10;
  696.     mt_aud.indexhi = 0;    /* seek ignores index */
  697.     mt_aud.index = 0;
  698.     mt_aud.seektype = MTAUDPOSN_PROG;
  699.  
  700.     if (perform_seek(fd, &mt_aud, maxretry) == 0) {
  701.     fprintf(stderr,"seek failed.\n");
  702.     return 0;
  703.     }
  704.  
  705.     if (verbose) {
  706.     printf("done\n");
  707.     }
  708.  
  709.     return 1;
  710. }
  711.  
  712. void
  713. seek_eot(int fd)
  714. {
  715. }
  716.  
  717. int
  718. seek_bot(int fd)
  719. {
  720.     struct mtop mtc;
  721.     struct mtaudio mta;
  722.     struct mtget mtg;
  723.  
  724.     /*
  725.      * Get some information about the DAT media
  726.      * We'll use this momentarily.
  727.      */
  728.     if (ioctl(fd, MTIOCGET, &mtg) < 0) {
  729.         perror("Couldn't issue MTIOCGET");
  730.     return(0);
  731.     }
  732.  
  733.     if (verbose) {
  734.         printf("rewinding...");
  735.         fflush(stdout);
  736.     }
  737.  
  738.     /*
  739.      * rewind the tape.
  740.      * Note that a rewind does not block. The rewind goes on while
  741.      * the program continues. The first write will block until
  742.      * the rewind completes. 
  743.      * We want the drive in audio mode here because BOT is different
  744.      * between data and audio modes (data mode rewinds to logical
  745.      * BOT, which is a little ways into the tape, and we want real
  746.      * BOT). 
  747.      */
  748.     if ((mtg.mt_erreg & (CT_AUD_MED >> 16)) == 0 && 
  749.         (mtg.mt_dsreg & CT_BOT)) {
  750.         /*
  751.          * firmware bug workaround. Tapes which have previously 
  752.          * been written with non-audio data are considered "data
  753.          * tapes." Their format differs from that of audio tapes. 
  754.          * If the tape in the drive  is considered a data tape, and
  755.          * the drive thinks it's at BOT, we want to move it off 
  756.          * BOT so that the drive will really rewind it when we issue  
  757.          * MTREW. Can't do a read, since a read of a data tape in 
  758.          * audio mode will fail. The write will force the medium to  
  759.          * become an audio tape.
  760.          */
  761.     if (verbose) {
  762.             printf("fixing a data tape at BOT to be an audio tape at BOT\n");
  763.     }
  764.         if (write(fd,&outframe,sizeof(DTFRAME)) < 0) {
  765.         perror("write failed");
  766.         return 0;
  767.     }
  768.     }
  769.     mtc.mt_op = MTREW;
  770.     mtc.mt_count = 1;
  771.     if (ioctl(fd, MTIOCTOP, &mtc) < 0) {
  772.     perror("rewind failed");
  773.     return 0;
  774.     }
  775.  
  776.     /*
  777.      * wait for the rewind to complete.
  778.      */
  779.     do {
  780.     if (ioctl(fd, MTIOCGET, &mtg) < 0) {
  781.         perror("DAT seek failed");
  782.         return 0;
  783.     }
  784.     } while (mtg.mt_erreg & (CT_SEEKING >> 16));
  785.  
  786.     if (verbose) {
  787.     printf("done.\n");
  788.     }
  789.  
  790.     tape_pos_unknown = 0;
  791.     last_cmd = OP_SEEK;
  792.     reset_timecodes();
  793. }
  794.  
  795. int
  796. write_bot(int fd)
  797. {
  798.     int i;
  799.     struct dttimepack *tpp;
  800.     struct dttimecode *tcp;
  801.  
  802.     if (verbose) {
  803.         printf("writing lead-in...");
  804.         fflush(stdout);
  805.     }
  806.  
  807.     /*
  808.      * Set the lead-in subcodes in our template frame
  809.      * Program no. of 0xB denotes lead-in.
  810.      */
  811.     outframe.subcode.sid.pno1 = 0;
  812.     outframe.subcode.sid.pno2 = outframe.subcode.sid.pno3 = 0xB;   /* BOT */
  813.     outframe.subcode.sid.ctrlid =  DTS_START;
  814.  
  815.     /*
  816.      * Mark the timecodes as invalid. 
  817.      * Also put 0xBB into the pno in the packs, indicating BOT. This 
  818.      * covers us no matter where a given drive snags its pno.
  819.      */
  820.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  821.     tcp = &tpp->tc;
  822.     tcp->hhi = tcp->hlo =
  823.     tcp->mhi = tcp->mlo = tcp->shi = tcp->slo = tcp->fhi = tcp->flo = 0xA;
  824.     tpp->pno1 = 0;
  825.     tpp->pno2 = tpp->pno3 = 0xB;   /* BOT */
  826.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  827.     tcp = &tpp->tc;
  828.     tcp->hhi = tcp->hlo =
  829.     tcp->mhi = tcp->mlo = tcp->shi = tcp->slo = tcp->fhi = tcp->flo = 0xA;
  830.     tpp->pno1 = 0;
  831.     tpp->pno2 = tpp->pno3 = 0xB;   /* BOT */
  832.    
  833.     /* clear the audio in the template frame */
  834.     bzero(&outframe.audio,DTDA_DATASIZE);
  835.  
  836.     /*
  837.      * Write the template frame to the tape to make the leader
  838.      */
  839.     for (i = 0; i < 120; i++) {
  840.         if ((write(fd, &outframe, sizeof(DTFRAME))) < 0) {
  841.             perror("tape write failed on leader");
  842.             return 0;
  843.         }
  844.     }
  845.  
  846.     last_cmd = OP_WRITE;
  847.     tape_pos_unknown = 0;
  848.     reset_timecodes();        /* set timecodes to 0:0:0:0 and pno to 1 */
  849.  
  850.     if (verbose) {
  851.         printf("done.\n");
  852.     }
  853. }
  854.  
  855. void
  856. set_index(int i)
  857. {
  858.     struct dttimepack *tpp;
  859.  
  860.     index = i;
  861.     if (verbose) {
  862.         printf("setting index to %d\n",index);
  863.     }
  864.  
  865.     /*
  866.      * set up the subcode bits
  867.      */
  868.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  869.     tpp->index.dhi = index / 10;
  870.     tpp->index.dlo = index % 10;
  871.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  872.     tpp->index.dhi = index / 10;
  873.     tpp->index.dlo = index % 10;
  874.     /* ...and we don't bother with r-time */
  875. }
  876.  
  877.  
  878. void
  879. set_program(int p)
  880.     int rem;
  881.     struct dttimepack *tpp;
  882.     struct dttimecode *tcp;
  883.  
  884.     if (verbose) {
  885.         printf("setting program to %d\n",p);
  886.     }
  887.  
  888.     program = p;
  889.  
  890.     /*
  891.      * set up the subcode bits
  892.      * first we do a-time
  893.      */
  894.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  895.  
  896.     tpp->pno1 = outframe.subcode.sid.pno1 = p / 100;
  897.     rem = p % 100;
  898.     tpp->pno2 = outframe.subcode.sid.pno2 = rem / 10;
  899.     tpp->pno3 = outframe.subcode.sid.pno3 = rem % 10;
  900.  
  901.     /* 
  902.      * now we do p-time 
  903.      * we zero p-time when we change program numbers.
  904.      * The DAT spec sez that program time is set to zero at start-of-
  905.      * program, and increments throughout the program. The start-of-
  906.      * program is where the first nonzero index occurs within the program.
  907.      */
  908.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  909.     tcp = &tpp->tc;
  910.  
  911.     tcp->hhi = 0;
  912.     tcp->hlo = 0;
  913.     tcp->mhi = 0;
  914.     tcp->mlo = 0;
  915.     tcp->shi = 0;
  916.     tcp->slo = 0;
  917.     tcp->fhi = 0;
  918.     tcp->flo = 0;
  919.     tpp->pno1 = outframe.subcode.sid.pno1;
  920.     tpp->pno2 = outframe.subcode.sid.pno2;
  921.     tpp->pno3 = outframe.subcode.sid.pno3;
  922.  
  923.     /* ...and we don't bother with r-time */
  924.  
  925.     /*
  926.      * now we set it up so that the next 300 frames
  927.      * have the start id bit set, indicating start-of-program.
  928.      * DAT spec sez START must be set for 300 frames at start-of-program
  929.      * and PRIORITYID must be set whenever program # is valid.
  930.      */
  931.     outframe.subcode.sid.ctrlid |= (DTS_PRIORITYID | DTS_START);
  932.     startidframes = 300;
  933. }
  934.  
  935. void
  936. inc_program()
  937. {
  938.     set_program(program+1);
  939. }
  940.  
  941. void
  942. inc_index()
  943. {
  944.     set_index(index+1);
  945. }
  946.  
  947. void
  948. fix_parity()
  949. {
  950.     volatile unchar *pp;
  951.     int i;
  952.  
  953.     /*
  954.      * calculate the parity bytes for the packs we are using.
  955.      */
  956.     for(i = 0; i<outframe.subcode.sid.numpacks; i++) {
  957.         pp = (volatile unchar *)&outframe.subcode.packs[i];
  958.         outframe.subcode.packs[i].parity
  959.             = pp[0] ^ pp[1] ^ pp[2] ^ pp[3] ^ pp[4] ^ pp[5] ^ pp[6];
  960.     }
  961. }
  962.  
  963. void
  964. increment_time()
  965. {
  966.     struct dttimepack *tpp;
  967.     struct dttimecode *tcp;
  968.  
  969.     tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  970.     tcp = &tpp->tc;
  971.     DTinctime(tcp);
  972.     /*
  973.      * The DAT spec states that when index=0, ptime stays
  974.      * at 0. We therefore only increment for a nonzero index.
  975.      */
  976.     if (index != 0) {
  977.         tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_PTIME-1];
  978.         tcp = &tpp->tc;
  979.         DTinctime(tcp);
  980.     }
  981.  
  982.     if (startidframes > 0) {
  983.         startidframes--;
  984.         if(startidframes==0) {
  985.             /* shut off start ID bit after startidframes */
  986.             outframe.subcode.sid.ctrlid &= ~DTS_START;
  987.         }
  988.     }
  989. }
  990.  
  991. void
  992. pause()
  993. {
  994.     char x[80];
  995.  
  996.     printf("Program paused. Hit return to continue.\n");
  997.     gets(x);
  998. }
  999.  
  1000. void
  1001. swapcopy(ushort *a, ushort *b, int n)
  1002. {
  1003.     ushort *done = a + n;
  1004.     while(a != done) {
  1005.         /* DAT audio frames must have the audio byte-swapped */
  1006.         *b++ = ((*a & 0xff) << 8)+(*a >> 8);
  1007.         a++;
  1008.     }
  1009. }
  1010.  
  1011. int
  1012. read_frames(int fd, char *filename, int nframes) 
  1013. {
  1014.     AFfilehandle file=0;
  1015.     AFfilesetup fset;
  1016.     int sz = 0,once=0;
  1017.     int i;
  1018.     struct dttimepack *tpp;
  1019.     struct dttimecode *tcp;
  1020.  
  1021.  
  1022.     if (verbose) {
  1023.     printf("writing %d frames to %s ...",nframes,filename);
  1024.     fflush(stdout);
  1025.     }
  1026.  
  1027.     while (--nframes >= 0) {
  1028.         if ((read(fd, &inframe, sizeof(DTFRAME))) < 0) {
  1029.             perror("tape read failed");
  1030.             return 0;
  1031.     }
  1032.         last_cmd = OP_READ;
  1033.         tape_pos_unknown = 1;
  1034.  
  1035.         /*
  1036.          * get the program number from the frame
  1037.          */
  1038.         switch(inframe.subcode.sid.pno3) {
  1039.         case 0xa :
  1040.             /* unused program number -- ignore */
  1041.             break;
  1042.         case 0xb :
  1043.             /* bot */
  1044.             if (!once && verbose) {
  1045.             printf("skipping BOT...");
  1046.             fflush(stdout);
  1047.          }
  1048.         once=1;
  1049.         continue;
  1050.         case 0xe :
  1051.             /* eot */
  1052.             if (verbose) printf("stopped at EOT\n");
  1053.         if (file) AFclosefile(file);
  1054.             return 0;
  1055.         default:
  1056.         break;
  1057.         }
  1058.      
  1059.     if (!file) {
  1060.             fset = AFnewfilesetup();
  1061.             AFinitchannels(fset,AF_DEFAULT_TRACK,2);
  1062.             switch (inframe.subcode.mid.sampfreq) {
  1063.         case DT_FREQ32000 :
  1064.             sz = DTDA_DATASIZE32K/sizeof(short);
  1065.                     AFinitrate(fset,AF_DEFAULT_TRACK,32000);
  1066.                  break;
  1067.             case DT_FREQ44100 :
  1068.             sz = DTDA_DATASIZE44K/sizeof(short);
  1069.                     AFinitrate(fset,AF_DEFAULT_TRACK,44100);
  1070.                  break;
  1071.         case DT_FREQ48000 :
  1072.             sz = DTDA_DATASIZE48K/sizeof(short);
  1073.                     AFinitrate(fset,AF_DEFAULT_TRACK,48000);
  1074.                  break;
  1075.             }
  1076.     
  1077.             file = AFopenfile(filename, "w", fset);
  1078.         AFfreefilesetup(fset);
  1079.             if (file == 0) {
  1080.         fprintf(stderr,"Couldn't open output file %s\n",filename);
  1081.         return 0;
  1082.             }
  1083.     }
  1084.  
  1085.     swapcopy((ushort *)&inframe.audio,(ushort *)&inframe.audio,sz);
  1086.         if (AFwriteframes(file, AF_DEFAULT_TRACK, &inframe.audio,
  1087.         sz / 2) != sz/2) {
  1088.             fprintf(stderr,"file write failed (is your disk full?)\n");
  1089.             return 0;
  1090.     }
  1091.     
  1092.     }
  1093.  
  1094.     if (file) AFclosefile(file);
  1095.     if (verbose) {
  1096.     printf("done.\n");
  1097.     }
  1098. }
  1099.  
  1100. int
  1101. read_file(int fd, char *filename, int endprog, int h, int m, int s, int f)
  1102. {
  1103.     AFfilehandle file=0;
  1104.     AFfilesetup fset;
  1105.     int sz = 0,once=0;
  1106.     int i;
  1107.     struct dttimepack *tpp;
  1108.     struct dttimecode *tcp;
  1109.  
  1110.  
  1111.     if (verbose) {
  1112.     printf("writing to %s ...",filename);
  1113.     fflush(stdout);
  1114.     }
  1115.  
  1116.     while (1) {
  1117.         if ((read(fd, &inframe, sizeof(DTFRAME))) < 0) {
  1118.             perror("tape read failed");
  1119.             return 0;
  1120.     }
  1121.         last_cmd = OP_READ;
  1122.         tape_pos_unknown = 1;
  1123.  
  1124.         /*
  1125.          * get the program number from the frame
  1126.          */
  1127.         switch(inframe.subcode.sid.pno3) {
  1128.         case 0xa :
  1129.             /* unused program number -- ignore */
  1130.             break;
  1131.         case 0xb :
  1132.             /* bot */
  1133.             if (!once && verbose) {
  1134.             printf("skipping BOT...");
  1135.             fflush(stdout);
  1136.          }
  1137.         once=1;
  1138.         continue;
  1139.         case 0xe :
  1140.             /* eot */
  1141.             if (verbose) printf("stopped at EOT\n");
  1142.         if (file) AFclosefile(file);
  1143.             return 0;
  1144.         default:
  1145.                 program = DTpnotodec(inframe.subcode.sid.pno1, 
  1146.                 inframe.subcode.sid.pno2, inframe.subcode.sid.pno3);
  1147.     
  1148.             outframe.subcode.sid.pno1 = inframe.subcode.sid.pno1;
  1149.             outframe.subcode.sid.pno2 = inframe.subcode.sid.pno2;
  1150.             outframe.subcode.sid.pno3 = inframe.subcode.sid.pno3;
  1151.         if (endprog && program == endprog) {
  1152.             if (file) AFclosefile(file);
  1153.             if (verbose) printf("found program %d, stopping\n",endprog);
  1154.             return 0;
  1155.         }
  1156.             break;
  1157.         }
  1158.     if (endprog == 0 ) {
  1159.             tpp = (struct dttimepack *)&inframe.subcode.packs[DTP_ATIME-1];
  1160.         tcp = &tpp->tc;
  1161.             if (DTtcvalid(tcp)) {
  1162.             if (f == (tcp->fhi * 10 + tcp->flo) && 
  1163.             s == (tcp->shi * 10 + tcp->slo) &&
  1164.             m == (tcp->mhi * 10 + tcp->mlo) &&
  1165.             h == (tcp->hhi * 10 + tcp->hlo)) {
  1166.             if (file) AFclosefile(file);
  1167.             if (verbose) printf("found timecode %d:%d:%d:%d, stopping\n",h,m,s,f);
  1168.             return 0;
  1169.         }
  1170.         }
  1171.     }
  1172.      
  1173.     if (!file) {
  1174.             fset = AFnewfilesetup();
  1175.             AFinitchannels(fset,AF_DEFAULT_TRACK,2);
  1176.             switch (inframe.subcode.mid.sampfreq) {
  1177.         case DT_FREQ32000 :
  1178.             sz = DTDA_DATASIZE32K/sizeof(short);
  1179.                     AFinitrate(fset,AF_DEFAULT_TRACK,32000);
  1180.                  break;
  1181.             case DT_FREQ44100 :
  1182.             sz = DTDA_DATASIZE44K/sizeof(short);
  1183.                     AFinitrate(fset,AF_DEFAULT_TRACK,44100);
  1184.                  break;
  1185.         case DT_FREQ48000 :
  1186.             sz = DTDA_DATASIZE48K/sizeof(short);
  1187.                     AFinitrate(fset,AF_DEFAULT_TRACK,48000);
  1188.                  break;
  1189.             }
  1190.     
  1191.             file = AFopenfile(filename, "w", fset);
  1192.         AFfreefilesetup(fset);
  1193.             if (file == 0) {
  1194.         fprintf(stderr,"Couldn't open output file %s\n",filename);
  1195.         return 0;
  1196.             }
  1197.     }
  1198.  
  1199.     swapcopy((ushort *)&inframe.audio,(ushort *)&inframe.audio,sz);
  1200.         if (AFwriteframes(file, AF_DEFAULT_TRACK, &inframe.audio,
  1201.         sz / 2) != sz/2) {
  1202.             fprintf(stderr,"file write failed (is your disk full?)\n");
  1203.             return 0;
  1204.     }
  1205.     
  1206.     }
  1207.  
  1208.     if (verbose) {
  1209.     printf("done.\n");
  1210.     }
  1211. }
  1212.  
  1213. int
  1214. write_file(int fd, char *filename)
  1215. {
  1216.     AFfilehandle file;
  1217.     int i;
  1218.  
  1219.     file = AFopenfile(filename, "r", 0);
  1220.     if (file == 0) {
  1221.     fprintf(stderr,"Couldn't open input file %s\n",filename);
  1222.     return 0;
  1223.     }
  1224.     if (AFgetchannels(file,AF_DEFAULT_TRACK) != 2) {
  1225.     fprintf(stderr,"Must be a stereo file\n");
  1226.     return 0;
  1227.     }
  1228.  
  1229.     if (tape_pos_unknown) {
  1230.     if (verbose) {
  1231.         printf("getting tape position...\n");
  1232.     }
  1233.     if (get_tape_pos(fd,0) == 0) {
  1234.         fprintf(stderr,"Couldn't get tape position: silence failed\n");
  1235.         return 0;
  1236.     }
  1237.     }
  1238.     if (!new_firmware && last_cmd == OP_READ) {
  1239.     /* 
  1240.      * workaround a firmware bug. writes can't immediately follow
  1241.      * reads, so we seek to the location of the last read, and 
  1242.      * write it back to the tape, then continue.
  1243.      */
  1244.     seek_to_last_read(fd,1);
  1245.     }
  1246.  
  1247.     if (verbose) {
  1248.     printf("writing %s ...",filename);
  1249.     fflush(stdout);
  1250.     }
  1251.  
  1252.     while (i = AFreadframes(file, AF_DEFAULT_TRACK, &outframe.audio,
  1253.     samps_per_frame / 2)) {
  1254.     if (i) {
  1255.             fix_parity();
  1256.         if (i < samps_per_frame / 2) {
  1257.             bzero(((short *)&outframe.audio)+2*i,samps_per_frame - 2 * i);
  1258.         }
  1259.         swapcopy((ushort *)&outframe.audio,(ushort *)&outframe.audio,2*i);
  1260.             if ((write(fd, &outframe, sizeof(DTFRAME))) < 0) {
  1261.                 perror("tape write failed");
  1262.                 return 0;
  1263.         }
  1264.     }
  1265.         last_cmd = OP_WRITE;
  1266.         tape_pos_unknown = 0;
  1267.     increment_time();
  1268.     }
  1269.  
  1270.     if (verbose) {
  1271.     printf("done.\n");
  1272.     }
  1273. }
  1274.  
  1275. int
  1276. write_testpat(int fd, int nframes)
  1277. {
  1278.     unsigned long i,j;
  1279.     struct dttimecode *tcp;
  1280.     struct dttimepack *tpp;
  1281.     unsigned long x;
  1282.     unsigned long *p;
  1283.  
  1284.     if (verbose) {
  1285.         printf("writing %d frames of test-pattern...",nframes);
  1286.         fflush(stdout);
  1287.     }
  1288.  
  1289.     if (tape_pos_unknown) {
  1290.     if (verbose) {
  1291.         printf("getting tape position...\n");
  1292.             fflush(stdout);
  1293.     }
  1294.     if (get_tape_pos(fd,0) == 0) {
  1295.         fprintf(stderr,"Couldn't get tape position: test-pattern failed\n");
  1296.         return 0;
  1297.     }
  1298.     }
  1299.     if (!new_firmware && last_cmd == OP_READ) {
  1300.     /* 
  1301.      * workaround a firmware bug. writes can't immediately follow
  1302.      * reads, so we seek to the location of the last read, and 
  1303.      * write it back to the tape, then continue.
  1304.      */
  1305.     seek_to_last_read(fd,1);
  1306.     }
  1307.  
  1308.     for (i = 0; i < nframes; i++) {
  1309.         fix_parity();
  1310.     /*
  1311.      * make the data a function of timecode & position within frame.
  1312.      * this allows us to verify the data on a subsequent read.
  1313.      */
  1314.         tpp = (struct dttimepack *)&outframe.subcode.packs[DTP_ATIME-1];
  1315.         tcp = &tpp->tc;
  1316.     x = (tcp->hhi << 28) | (tcp->hlo << 24) 
  1317.       | (tcp->mhi << 20) | (tcp->mlo << 16) 
  1318.       | (tcp->shi << 12) | (tcp->slo << 8) 
  1319.       | (tcp->fhi << 4) | tcp->flo;
  1320.     p = (unsigned long *) &outframe.audio;
  1321.     for (j = 0; j < DTDA_DATASIZE; j += sizeof(long)) {
  1322.         *p++ = x++;
  1323.     }
  1324.  
  1325.         if ((write(fd, &outframe, sizeof(DTFRAME))) < 0) {
  1326.             perror("tape write failed");
  1327.             return 0;
  1328.         }
  1329.         last_cmd = OP_WRITE;
  1330.         tape_pos_unknown = 0;
  1331.     increment_time();
  1332.     }
  1333.  
  1334.  
  1335.     if (verbose) {
  1336.         printf("done.\n");
  1337.     }
  1338. }
  1339.  
  1340. int
  1341. write_silence(int fd, int nframes)
  1342. {
  1343.     unsigned long i;
  1344.  
  1345.     if (verbose) {
  1346.         printf("writing %d frames of silence...",nframes);
  1347.         fflush(stdout);
  1348.     }
  1349.  
  1350.     if (tape_pos_unknown) {
  1351.     if (verbose) {
  1352.         printf("getting tape position...\n");
  1353.             fflush(stdout);
  1354.     }
  1355.     if (get_tape_pos(fd,0) == 0) {
  1356.         fprintf(stderr,"Couldn't get tape position: silence failed\n");
  1357.         return 0;
  1358.     }
  1359.     }
  1360.     if (!new_firmware && last_cmd == OP_READ) {
  1361.     /* 
  1362.      * workaround a firmware bug. writes can't immediately follow
  1363.      * reads, so we seek to the location of the last read, and 
  1364.      * write it back to the tape, then continue.
  1365.      */
  1366.     seek_to_last_read(fd,1);
  1367.     }
  1368.  
  1369.     /* set the audio in the template frame to zero */
  1370.     bzero(&outframe.audio,DTDA_DATASIZE);
  1371.  
  1372.     for (i = 0; i < nframes; i++) {
  1373.         fix_parity();
  1374.         if ((write(fd, &outframe, sizeof(DTFRAME))) < 0) {
  1375.             perror("tape write failed");
  1376.             return 0;
  1377.         }
  1378.         last_cmd = OP_WRITE;
  1379.         tape_pos_unknown = 0;
  1380.     increment_time();
  1381.     }
  1382.  
  1383.  
  1384.     if (verbose) {
  1385.         printf("done.\n");
  1386.     }
  1387. }
  1388.  
  1389. void
  1390. set_rate(int r)
  1391. {
  1392.     /*
  1393.      * set up the rate bits
  1394.      */
  1395.     if (verbose) {
  1396.     printf("setting rate to %d\n",r);
  1397.     }
  1398.     switch(r) {
  1399.     case 32 :
  1400.             outframe.subcode.mid.sampfreq = DT_FREQ32000;
  1401.         samps_per_frame = DTDA_NUMSAMPS32K;
  1402.         break;
  1403.     case 48 :
  1404.             outframe.subcode.mid.sampfreq = DT_FREQ48000;
  1405.         samps_per_frame = DTDA_NUMSAMPS48K;
  1406.         break;
  1407.     case 44 :
  1408.     default :
  1409.             outframe.subcode.mid.sampfreq = DT_FREQ44100;
  1410.         samps_per_frame = DTDA_NUMSAMPS44K;
  1411.         break;
  1412.     }
  1413. }
  1414.  
  1415. void
  1416. quit()
  1417. {
  1418.     exit(0);
  1419. }
  1420.  
  1421. void 
  1422. dummy_error(long a, const char *b)
  1423. {
  1424. }
  1425.  
  1426. main(int argc, char **argv)
  1427. {
  1428.     int status;
  1429.     int n = 1;
  1430.     int i;
  1431.     int excl_id;            /* id as returned by mediad */
  1432.     int maj, min;            /* dat firmware rel major&minor # */
  1433.     struct mtop mtc;
  1434.  
  1435.     if (argc>3) {
  1436.     fprintf(stderr, "usage: %s [-q] [filename]\n",argv[0]);
  1437.     exit(-1);
  1438.     }
  1439.     while(--argc) {
  1440.         if (!strncmp(argv[argc],"-q")) {
  1441.         verbose=0;
  1442.     }
  1443.     else {
  1444.         if (!freopen(argv[argc],"r", stdin)) {
  1445.          fprintf(stderr, "error: could not open %s for input\n",argv[argc]);
  1446.         exit(-1);
  1447.         }
  1448.     }
  1449.     }
  1450.  
  1451.     AFseterrorhandler(dummy_error);
  1452.     
  1453.     /*
  1454.      * Ask mediad for exclusive access to the DAT drive.
  1455.      */
  1456.     excl_id = mediad_get_exclusiveuse(datdev, argv[0]);
  1457.  
  1458.     /*
  1459.      * Open the DAT drive
  1460.      */
  1461.     dat = open(datdev, O_RDWR);
  1462.     if (dat < 0) {
  1463.         perror("Could not open DAT drive:");
  1464.         exit(-1);
  1465.     }
  1466.  
  1467.     if (get_firmware_revision(dat, &maj, &min) < 0) {
  1468.         fprintf(stderr,"Couldn't get DAT firmware revision\n");
  1469.         exit(-1);
  1470.     }
  1471.     /* pre-2.63 DAT drives don't work with audio */
  1472.     if (maj < 2 || (maj == 2 && min < 63)) {
  1473.         fprintf(stderr,"DAT firmware rev %d.%d is too old -- you must have 2.63 or greater\n",maj,min);
  1474.         exit(-1);
  1475.     }
  1476.     new_firmware = (min<72 && maj == 2) ? 0 : 1;
  1477.  
  1478.     /*
  1479.      * Put the DAT drive in audio mode. 
  1480.      */
  1481.     mtc.mt_op = MTAUD;
  1482.     mtc.mt_count = 1;
  1483.     if (ioctl(dat, MTIOCTOP, &mtc) < 0) {
  1484.         if (oserror() != EAGAIN) {
  1485.             perror("Couldn't put DAT into audio mode");
  1486.             exit(-1);
  1487.         }
  1488.     }
  1489.  
  1490.     /*
  1491.      * initialize a DAT frame
  1492.      */ 
  1493.     bzero(&outframe,sizeof(DTFRAME));
  1494.  
  1495.     /*
  1496.      * set up the rate bits
  1497.      */
  1498.     outframe.subcode.mid.sampfreq = DT_FREQ44100;
  1499.  
  1500.     /*
  1501.      * set up all the timecode packs
  1502.      */
  1503.     reset_timecodes();
  1504.  
  1505.     if(verbose) {
  1506.         printf("DAT tape ready... lay it on me.\n");
  1507.     }
  1508.  
  1509.     while (1) {
  1510.     yyparse();
  1511.     }
  1512. }
  1513.  
  1514. yywrap()
  1515. {
  1516.     return 0;
  1517. }
  1518.  
  1519. yyerror(char *s)
  1520. {
  1521.     fprintf(stderr,"?%s\n",s);
  1522. }
  1523.